#!/usr/bin/perl
use Test::More;

#
# These tests cover the net/sctp security hooks as discussed in kernel tree:
#     Documentation/security/SCTP.rst
# The only two places in SCTP code not tested as they need unusual sctp
# packets to be sent are:
#   net/sctp/sm_statefuns.c sctp_sf_do_unexpected_init - assoc_request
#   net/sctp/sm_statefuns.c sctp_sf_do_5_2_4_dupcook - assoc_request
#
# Network traffic can be followed using tshark(1):
#        tshark -O sctp,ipv6,ip,cipso,calipso -P -x -i any
#

BEGIN {
    $basedir = $0;
    $basedir =~ s|(.*)/[^/]*|$1|;

    # allow SCTP info to be shown during tests
    $v = $ARGV[0];
    if ($v) {
        if ( $v ne "-v" ) {
            plan skip_all => "Invalid option (use -v)";
        }
    }
    else {
        $v = " ";
    }

    # check if sctp enabled
    if ( system("checksctp 2> /dev/null") != 0 ) {
        plan skip_all => "SCTP not supported";
    }
    else {
        $test_count = 75;

        # Set up a GRE tunnel over loopback to ensure we have enough addresses
        # for the ASCONF tests.
        system "ip link add mygre type gretap local 127.0.0.1 remote 127.0.0.1";
        system "ip addr add 10.123.123.123 dev mygre";
        system "ip link set mygre up";

        # asconf parameter tests require two local non-loopback addresses.
        $ipaddress_list = `ip -o addr show up scope global`;
        $test_asconf    = 0;
        $count          = 0;
        $ipaddress[0]   = 0;
        $ipaddress[1]   = 0;

        for my $line ( split /\n/, $ipaddress_list ) {
            if ( $line =~ /inet ([^ \/]+)/ && $count < 2 ) {
                $ipaddress[$count] = $1;
                $count++;
            }
        }

        if ( $ipaddress[1] ne 0 and $ipaddress[0] ne $ipaddress[1] ) {
            $test_count += 3;
            $test_asconf = 1;
        }

        # Determine if CALIPSO supported by netlabelctl(8) and kernel.
        $test_calipso = 0;
        $netlabelctl  = `netlabelctl -V`;
        $netlabelctl =~ s/\D//g;
        $kvercur = `uname -r`;
        chomp($kvercur);
        $kvermincalipso = "4.8";

        $rc = `$basedir/../kvercmp $kvercur $kvermincalipso`;
        if ( $netlabelctl gt "021" && $rc > 0 ) {
            $test_count += 13;
            $test_calipso = 1;
        }

        # Determine if nftables has secmark support
        $test_nft = 0;

        $rc = system("nft -c -f $basedir/nftables-load 2>/dev/null");
        if ( $rc == 0 ) {
            $test_count += 8;
            $test_nft = 1;
        }
    }

    plan tests => $test_count;
}

sub server_start {
    my ( $runcon_args, $prog, $args ) = @_;
    my $pid;

    system("mkfifo $basedir/flag");

    if ( ( $pid = fork() ) == 0 ) {
        exec "runcon $runcon_args $basedir/$prog -f $basedir/flag $args";
    }

    # Wait for it to initialize.
    system("read -t 5 <>$basedir/flag");
    return $pid;
}

sub server_end {
    my ($pid) = @_;

    kill KILL, $pid;
    waitpid $pid, 0;
    system("rm -f $basedir/flag");
}

#
# NOTE: direction flow is given as Client->Server (STREAM->SEQ)
#

#
########################## Test base configuration ##########################
#
print "# Testing base configuration.\n";

# Start the stream server.
$pid =
  server_start( "-t test_sctp_server_t", "sctp_server", "$v -n stream 1035" );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2).
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3).
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -x -e nopeer stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server SEQ->STREAM with no client connect(2).
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -n -e nopeer seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server SEQ->STREAM.
$result = system
  "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
ok( $result eq 0 );

# Verify that the client cannot communicate with server when using port < 1024 STREAM->STREAM.
# deny sctp_socket { name_connect }
$result = system
"runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1023 2>&1";
ok( $result >> 8 eq 8 );

# Kill the stream server.
server_end($pid);

# Verify that the server cannot start when using port < 1024.
# deny sctp_socket { name_bind }
$result =
  system "runcon -t test_sctp_server_t -- $basedir/sctp_bind $v stream 80 2>&1";
ok($result);

#
############################### CONNECTX #####################################
#
# net/sctp/socket.c sctp_setsockopt_connectx() SCTP_SOCKOPT_CONNECTX
print "# Testing connectx.\n";

$result = system
"runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v stream 127.0.0.1 1035";
ok( $result eq 0 );

$result =
  system
  "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v seq ::1 1035";
ok( $result eq 0 );

$result =
  system
"runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v seq ::1 1035 2>&1";
ok( $result >> 8 eq 7 );

#
########################### SCTP_SENDMSG_CONNECT #############################
#
# net/sctp/socket.c sctp_sendmsg_new_asoc() SCTP_SENDMSG_CONNECT
print "# Testing SCTP_SENDMSG_CONNECT.\n";

$result =
  system
"runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v -n seq 127.0.0.1 1035";
ok( $result eq 0 );

$result =
  system
"runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v -n seq ::1 1035 2>&1";
ok( $result >> 8 eq 8 );

#
################################ BINDX #######################################
#
# net/sctp/socket.c sctp_setsockopt_bindx() SCTP_SOCKOPT_BINDX_ADD
print "# Testing bindx.\n";

$result =
  system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx $v -r stream 1035";
ok( $result eq 0 );

$result =
  system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx $v -r seq 1035";
ok( $result eq 0 );

$result =
  system
  "runcon -t test_sctp_deny_bindx_t $basedir/sctp_bindx $v -r seq 1035 2>&1";
ok( $result >> 8 eq 2 );

#
##################### Dynamic Address Reconfiguration #####################
#
# These tests require two non-loopback addresses.
#
# Server - setsockopt(SCTP_SET_PEER_PRIMARY_ADDR, $ipaddress[0]);
# net/sctp/sm_make_chunk.c sctp_process_asconf_param() SCTP_PARAM_SET_PRIMARY
# Server -> Client (Set $ipaddress[0] as primary - client acks)
#
# Server - sctp_bindx(SCTP_BINDX_ADD_ADDR, $ipaddress[1]);
# net/sctp/sm_make_chunk.c sctp_process_asconf_param() SCTP_PARAM_ADD_IP
# Server -> Client (Set $ipaddress[1] as primary - client acks)
#
# These are sent by the server and require bind permission. They are
# received by the client and the SCTP_PARAM_ADD_IP is validated when
# $ipaddress[1] is set for use via:
#    net/sctp/socket.c sctp_setsockopt_peer_primary_addr(setsockopt(SCTP_PRIMARY_ADDR))
# This requires the 'bind' permission, if not granted client exits with 51.
#

if ($test_asconf) {

    # To enable processing of ASCONF parameters SCTP_PARAM_SET_PRIMARY
    # and SCTP_PARAM_ADD_IP need to set:
    system("echo 1 > /proc/sys/net/sctp/addip_enable");
    system("echo 1 > /proc/sys/net/sctp/addip_noauth_enable");

    print "Testing Dynamic Address Reconfiguration\n";

    # Server should automatically exit after each test
    $pid = server_start(
        "-t sctp_asconf_params_server_t",
        "sctp_asconf_params_server",
        "$v $ipaddress[0] $ipaddress[1] 1035"
    );

    $result = system
"runcon -t sctp_asconf_params_client_t $basedir/sctp_asconf_params_client $v $ipaddress[0] 1035";
    ok( $result eq 0 );

    server_end($pid);

    $pid = server_start(
        "-t sctp_asconf_params_server_t",
        "sctp_asconf_params_server",
        "$v $ipaddress[0] $ipaddress[1] 1035"
    );

    print "Testing deny SCTP_PRIMARY_ADDR\n";
    $result = system
"runcon -t sctp_asconf_deny_pri_addr_client_t $basedir/sctp_asconf_params_client $v $ipaddress[0] 1035 2>&1";
    ok( $result >> 8 eq 51 );    # setsockopt(2) failed

    server_end($pid);

    #
    # This is a local only test as it's the neverallow rule that stops:
    #    server -> client sctp_socket { connect };
    #
    # Srv sends SCTP_PARAM_ADD_IP and SCTP_PARAM_SET_PRIMARY in ASCONF's
    # Client returns ASCONF_ACK's with 'Request refused - no authorization'
    $pid = server_start(
        "-t sctp_asconf_params_server_t",
        "sctp_asconf_params_server",
        "$v $ipaddress[0] $ipaddress[1] 1035"
    );

    print "Testing deny SCTP_PARAM_ADD_IP/SCTP_PARAM_SET_PRIMARY\n";
    $result = system
"runcon -t sctp_asconf_deny_param_add_client_t $basedir/sctp_asconf_params_client $v $ipaddress[0] 1035 2>&1";
    ok( $result >> 8 eq 11 );   # Client error 'Dynamic Address Reconfiguration'

    server_end($pid);

    system("echo 0 > /proc/sys/net/sctp/addip_enable");
    system("echo 0 > /proc/sys/net/sctp/addip_noauth_enable");
}

#
######################## Test NetLabel Configurations #######################
#
########################## Fallback peer Labeling ############################
#

# Load NetLabel configuration using "netlabel_sctp_peer_t" as the label.
print "# Testing NetLabel fallback peer labeling.\n";
system "/bin/sh $basedir/fb-label-load";

# Start stream server.
$pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v stream 1035" );

# Verify that authorized client can communicate with the server STREAM->STREAM.
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server SEQ->STREAM.
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that a client without peer { recv } permission cannot communicate with the server STREAM->STREAM.
$result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the stream server.
server_end($pid);

# Start seq server.
$pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v seq 1035" );

# Verify that authorized client can communicate with the server SEQ->SEQ.
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server STREAM->SEQ.
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream ::1 1035";
ok( $result eq 0 );

# Verify that a client using connect(2) without peer { recv } permission cannot communicate with the server SEQ->SEQ.
$result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Verify that a client using sctp_connectx(3) without peer { recv } permission cannot communicate with the server SEQ->SEQ.
$result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -x -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Verify that a client not using any connect without peer { recv } permission cannot communicate with the server SEQ->SEQ.
$result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -n -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
ok( $result >> 8 eq 13 );

# Kill the seq server.
server_end($pid);

system "/bin/sh $basedir/fb-label-flush";

#
#################### Test deny association permission ########################
#
# net/sctp/sm_statefuns.c sctp_sf_do_5_1B_init() assoc_request
print "# Testing deny association.\n";
system "/bin/sh $basedir/fb-deny-label-load";

$pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v stream 1035" );

# Verify that authorized client can communicate with the server STREAM->STREAM.
# This sets the servers initial peer context to netlabel_sctp_peer_t:s0
$result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that the server is denied this association as the client will timeout on connect.
$result = system
"runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e system_u:object_r:deny_assoc_sctp_peer_t:s0 stream ::1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the seq server.
server_end($pid);

system "/bin/sh $basedir/fb-deny-label-flush";

#
############################## CIPSO/IPv4 TAG 1 ###############################
#
print "# Testing CIPSO/IPv4 - TAG 1 using socket ip_option data\n";
system "/bin/sh $basedir/cipso-load-t1";

# Start the stream server for IPv4 only.
$pid = server_start(
    "-t test_sctp_server_t -l s0:c182.c192",
    "sctp_server",
    "$v -4 -i stream 1035"
);

# Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3).
$result = system
"runcon -t test_sctp_client_t -l s0:c182.c192 $basedir/sctp_client $v -x -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2).
$result = system
"runcon -t test_sctp_client_t -l s0:c182.c192 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level STREAM->STREAM.
$result = system
"runcon -t test_sctp_client_t -l s0:c182,c187,c190 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level SEQ->STREAM
$result = system
"runcon -t test_sctp_client_t -l s0:c189,c192 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client cannot communicate with the server using invalid level STREAM->STREAM.
# Fails with mlsconstrain peer { recv }
$result = system
"runcon -t test_sctp_client_t -l s0:c182.c193 -- $basedir/sctp_client $v stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the stream server.
server_end($pid);

# Start the seq server.
$pid = server_start(
    "-t test_sctp_server_t -l s0:c20.c300",
    "sctp_server",
    "$v -4 -i seq 1035"
);

# Verify that authorized client can communicate with the server. SEQ->SEQ
$result = system
"runcon -t test_sctp_client_t -l s0:c27.c28 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ.
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c30 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using SEQ->SEQ with diff valid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c24,c26,c27.c29 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that client cannot communicate with the server using SEQ->SEQ with invalid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c19.c100 -- $basedir/sctp_client $v -i seq 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# TAG 1 allows categories 0 to 239 to be sent, if greater then ENOSPC (No space left on device)
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c300 -- $basedir/sctp_client $v -i seq 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 7 );

# Kill server.
server_end($pid);

print "# Testing CIPSO/IPv4 - TAG 1 PEELOFF using socket ip_option data\n";

# Test sctp_peeloff(3) using 1 to Many SOCK_SEQPACKET
$pid = server_start(
    "-t test_sctp_server_t -l s0:c0.c10",
    "sctp_peeloff_server",
    "$v -4 -i 1035"
);

# Verify that authorized client can communicate with the server using SEQ->SEQ->Peeloff with same level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ->peeloff with same level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -x -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that client cannot communicate with the server using STREAM->SEQ->peeloff with invalid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c11 -- $basedir/sctp_client $v -x -i stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the seq server.
server_end($pid);

system "/bin/sh $basedir/cipso-flush";

#
############################## CIPSO/IPv4 TAG 2 ###############################
#
print "# Testing CIPSO/IPv4 - TAG 2 using socket ip_option data\n";
system "/bin/sh $basedir/cipso-load-t2";

# Start the stream server for IPv4 only.
$pid = server_start(
    "-t test_sctp_server_t -l s0:c782,c714,c769,c788,c803,c842,c864",
    "sctp_server", "$v -4 -i stream 1035" );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3).
$result = system
"runcon -t test_sctp_client_t -l s0:c782,c714,c769,c788,c803,c842,c864 $basedir/sctp_client $v -x -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2).
$result = system
"runcon -t test_sctp_client_t -l s0:c782,c714,c769,c788,c803,c842,c864 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level STREAM->STREAM.
$result = system
"runcon -t test_sctp_client_t -l s0:c769,c788,c803,c842,c864 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level SEQ->STREAM
$result = system
"runcon -t test_sctp_client_t -l s0:c769,c788,c803 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client cannot communicate with the server using invalid level STREAM->STREAM.
$result = system
"runcon -t test_sctp_client_t -l s0:c1023 -- $basedir/sctp_client $v stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the stream server.
server_end($pid);

# Start the seq server.
$pid = server_start(
    "-t test_sctp_server_t -l s0:c20.c335",
    "sctp_server",
    "$v -4 -i seq 1035"
);

# Verify that authorized client can communicate with the server. SEQ->SEQ
$result = system
"runcon -t test_sctp_client_t -l s0:c328.c333 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ.
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c34 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using SEQ->SEQ with diff valid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c30,c31,c335 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that client cannot communicate with the server using SEQ->SEQ with invalid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c19.c30 -- $basedir/sctp_client $v -i seq 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# TAG 2 allows a maximum of 15 categories in exchange, if greater then ENOSPC (No space left on device)
$result = system
"runcon -t test_sctp_client_t -l s0:c200.c216 -- $basedir/sctp_client $v -i seq 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 7 );

# Kill server.
server_end($pid);

print "# Testing CIPSO/IPv4 - TAG 2 PEELOFF using socket ip_option data\n";

# Test sctp_peeloff(3) using 1 to Many SOCK_SEQPACKET
$pid = server_start(
    "-t test_sctp_server_t -l s0:c0.c10",
    "sctp_peeloff_server",
    "$v -4 -i 1035"
);

# Verify that authorized client can communicate with the server using SEQ->SEQ->Peeloff with same level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ->peeloff with same level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -x -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that client cannot communicate with the server using STREAM->SEQ->peeloff with invalid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c11 -- $basedir/sctp_client $v -x -i stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the seq server.
server_end($pid);

system "/bin/sh $basedir/cipso-flush";

#
############################## CIPSO/IPv4 TAG 5 ###############################
#
print "# Testing CIPSO/IPv4 - TAG 5 using socket ip_option data\n";
system "/bin/sh $basedir/cipso-load-t5";

# Start the stream server for IPv4 only.
$pid = server_start(
    "-t test_sctp_server_t -l s0:c782,c714,c769,c788,c803,c842,c864",
    "sctp_server", "$v -4 -i stream 1035" );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3).
$result = system
"runcon -t test_sctp_client_t -l s0:c782,c714,c769,c788,c803,c842,c864 $basedir/sctp_client $v -x -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2).
$result = system
"runcon -t test_sctp_client_t -l s0:c782,c714,c769,c788,c803,c842,c864 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level STREAM->STREAM.
$result = system
"runcon -t test_sctp_client_t -l s0:c769,c788,c803,c842,c864 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level SEQ->STREAM
$result = system
"runcon -t test_sctp_client_t -l s0:c769,c788,c803 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client cannot communicate with the server using invalid level STREAM->STREAM.
$result = system
"runcon -t test_sctp_client_t -l s0:c1023 -- $basedir/sctp_client $v stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the stream server.
server_end($pid);

# Start the seq server.
$pid = server_start(
    "-t test_sctp_server_t -l s0:c20.c50",
    "sctp_server",
    "$v -4 -i seq 1035"
);

# Verify that authorized client can communicate with the server. SEQ->SEQ
$result = system
"runcon -t test_sctp_client_t -l s0:c28.c48 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ.
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c50 $basedir/sctp_client $v -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using SEQ->SEQ with diff valid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c30,c31,c35,c40.c45 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that client cannot communicate with the server using SEQ->SEQ with invalid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c20.c51 -- $basedir/sctp_client $v -i seq 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# TAG 2 allows a maximum of 7 ranges in exchange, if greater then ENOSPC (No space left on device)
$result = system
"runcon -t test_sctp_client_t -l s0:c20,c22,c24,c30.c33,c38,c42.c45,c48,c50 -- $basedir/sctp_client $v -i seq 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 7 );

# Kill server.
server_end($pid);

print "# Testing CIPSO/IPv4 - TAG 5 PEELOFF using socket ip_option data\n";

# Test sctp_peeloff(3) using 1 to Many SOCK_SEQPACKET
$pid = server_start(
    "-t test_sctp_server_t -l s0:c0.c10",
    "sctp_peeloff_server",
    "$v -4 -i 1035"
);

# Verify that authorized client can communicate with the server using SEQ->SEQ->Peeloff with same level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -i seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ->peeloff with same level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -x -i stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that client cannot communicate with the server using STREAM->SEQ->peeloff with invalid level.
$result = system
"runcon -t test_sctp_client_t -l s0:c0.c11 -- $basedir/sctp_client $v -x -i stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the seq server.
server_end($pid);

system "/bin/sh $basedir/cipso-flush";

#
################## CIPSO/IPv4 Full Labeling over Loopback ####################
#

print "# Testing CIPSO/IPv4 full labeling over loopback.\n";
system "/bin/sh $basedir/cipso-fl-load";

# Start the stream server for IPv4 only.
$pid =
  server_start( "-t test_sctp_server_t", "sctp_server", "$v -4 stream 1035" );

# Verify that authorized client can communicate with the server STREAM->STREAM.
$result = system
  "runcon -t test_sctp_client_t $basedir/sctp_client $v stream 127.0.0.1 1035";
ok( $result eq 0 );

# Verify a client without peer { recv } for client/server process cannot communicate with server STREAM->STREAM.
$result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v stream 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the stream server.
server_end($pid);

# Start the seq server for IPv4 only.
$pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v -4 seq 1035" );

# Verify that authorized client can communicate with the server SEQ->STREAM.
$result =
  system
  "runcon -t test_sctp_client_t $basedir/sctp_client $v seq 127.0.0.1 1035";
ok( $result eq 0 );

# Verify that a client without peer { recv } permission cannot communicate with the server SEQ->SEQ.
$result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v seq 127.0.0.1 1035 2>&1";
ok( $result >> 8 eq 6 );

# Kill the seq server.
server_end($pid);

system "/bin/sh $basedir/cipso-fl-flush";

#
############################### CALIPSO/IPv6 #################################
#

if ($test_calipso) {
    print "# Testing CALIPSO/IPv6 using socket ip_option data\n";
    system "/bin/sh $basedir/calipso-load";

    # Start the stream server.
    $pid = server_start(
"-t test_sctp_server_t -l  s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023",
        "sctp_server",
        "$v -i stream 1035"
    );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3).
    $result = system
"runcon -t test_sctp_client_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023  $basedir/sctp_client $v -x -i stream ::1 1035";
    ok( $result eq 0 );

# Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2).
    $result = system
"runcon -t test_sctp_client_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023  $basedir/sctp_client $v -i stream ::1 1035";
    ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level STREAM->STREAM.
    $result = system
"runcon -t test_sctp_client_t -l s0:c924,c726,c128,c330,c832,c534,c936,c138,c740,c42 $basedir/sctp_client $v -i stream ::1 1035";
    ok( $result eq 0 );

# Verify that authorized client can communicate with the server using different valid level SEQ->STREAM
    $result = system
"runcon -t test_sctp_client_t -l s0:c924,c726,c128,c330,c832,c534,c936,c138,c740,c42 $basedir/sctp_client $v -i seq ::1 1035";
    ok( $result eq 0 );

# Verify that authorized client cannot communicate with the server using invalid level STREAM->STREAM.
    $result = system
"runcon -t test_sctp_client_t -l s0:c8.c12 -- $basedir/sctp_client $v -i stream ::1 1035 2>&1";
    ok( $result >> 8 eq 6 );

    # Kill the stream server.
    server_end($pid);

    # Start the seq server.
    $pid = server_start(
        "-t test_sctp_server_t -l s0:c20.c50",
        "sctp_server",
        "$v -i seq 1035"
    );

    # Verify that authorized client can communicate with the server. SEQ->SEQ
    $result = system
"runcon -t test_sctp_client_t -l s0:c28.c48 $basedir/sctp_client $v -i seq ::1 1035";
    ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ.
    $result = system
"runcon -t test_sctp_client_t -l s0:c20.c50 $basedir/sctp_client $v -i stream ::1 1035";
    ok( $result eq 0 );

# Verify that authorized client can communicate with the server using SEQ->SEQ with diff valid level.
    $result = system
"runcon -t test_sctp_client_t -l s0:c20.c30,c31,c35,c40.c45 $basedir/sctp_client $v -i seq ::1 1035";
    ok( $result eq 0 );

# Verify that client cannot communicate with the server using SEQ->SEQ with invalid level.
    $result = system
"runcon -t test_sctp_client_t -l s0:c20.c51 $basedir/sctp_client $v -i seq ::1 1035 2>&1";
    ok( $result >> 8 eq 6 );

# Verify that client cannot communicate with the server using SEQ->SEQ with invalid level.
    $result = system
"runcon -t test_sctp_client_t -l s0:c19.c50 -- $basedir/sctp_client $v -i seq ::1 1035 2>&1";
    ok( $result >> 8 eq 6 );

    # Kill server.
    server_end($pid);

    print "# Testing CALIPSO/IPv6 PEELOFF using socket ip_option data\n";

    # Test sctp_peeloff(3) using 1 to Many SOCK_SEQPACKET
    $pid = server_start(
        "-t test_sctp_server_t -l s0:c0.c10",
        "sctp_peeloff_server",
        "$v -i 1035"
    );

# Verify that authorized client can communicate with the server using SEQ->SEQ->Peeloff with same level.
    $result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -i seq ::1 1035";
    ok( $result eq 0 );

# Verify that authorized client can communicate with the server using STREAM->SEQ->peeloff with same level.
    $result = system
"runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client $v -x -i stream ::1 1035";
    ok( $result eq 0 );

# Verify that client cannot communicate with the server using STREAM->SEQ->peeloff with invalid level.
    $result = system
"runcon -t test_sctp_client_t -l s0:c0.c11 -- $basedir/sctp_client $v -x -i stream ::1 1035 2>&1";
    ok( $result >> 8 eq 6 );

    # Kill the seq server.
    server_end($pid);

    system "/bin/sh $basedir/calipso-flush";
}

#
################## Test iptables/nftables configuration ######################
#
sub test_tables {

    # Start the stream server.
    $pid = server_start( "-t test_sctp_server_t",
        "sctp_server", "$v -n stream 1035" );

 # Verify that authorized client can communicate with the server STREAM->STREAM.
    $result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer stream 127.0.0.1 1035";
    ok( $result eq 0 );

# Verify that a client without packet { recv } permission cannot communicate with the server STREAM->STREAM.
    $result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream 127.0.0.1 1035 2>&1";
    ok( $result >> 8 eq 6 );

 # Verify that authorized client can communicate with the server STREAM->STREAM.
    $result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer stream ::1 1035";
    ok( $result eq 0 );

# Verify that a client without packet { recv } permission cannot communicate with the server STREAM->STREAM.
    $result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1035 2>&1";
    ok( $result >> 8 eq 6 );

    # Kill the stream server.
    server_end($pid);

    # Start the seq server.
    $pid =
      server_start( "-t test_sctp_server_t", "sctp_server", "$v -n seq 1035" );

    # Verify that authorized client can communicate with the server SEQ->SEQ.
    $result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq 127.0.0.1 1035";
    ok( $result eq 0 );

# Verify that a client without packet { recv } permission cannot communicate with the server SEQ->SEQ.
    $result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq 127.0.0.1 1035 2>&1";
    ok( $result >> 8 eq 6 );

    # Verify that authorized client can communicate with the server SEQ->SEQ.
    $result = system
"runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
    ok( $result eq 0 );

# Verify that a client without packet { recv } permission cannot communicate with the server SEQ->SEQ.
    $result = system
"runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq ::1 1035 2>&1";
    ok( $result >> 8 eq 6 );

    # Kill the seq server.
    server_end($pid);
}

print "# Testing iptables (IPv4/IPv6).\n";
system "/bin/sh $basedir/iptables-load";
test_tables();
system "/bin/sh $basedir/iptables-flush";

if ($test_nft) {
    print "# Testing nftables (IPv4/IPv6).\n";
    system "nft -f $basedir/nftables-load";
    test_tables();
    system "nft -f $basedir/nftables-flush";
}

system "ip link del mygre";

exit;
